/// socketpair(2) demo. 
/// Show how to communicate between two process(parent and child process).
/// IPC type: Unix domain socket
///
/// \note Build command:
///   $ g++ sockectpair.cpp -o sockectpair -pthread
///       Run command:
///   $ ./sockectpair
///
/// \see https://github.com/dagwieers/vsftpd

#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <iostream>
#include <cstring>
#include <thread>

using namespace std;

void sysutil_exit(int exit_code)
{
    _exit(exit_code);
}

void die(const char* p_text)
{
    sysutil_exit(2);
}

struct sysutil_socketpair_retval
{
    int socket_one;
    int socket_two;
};

struct sysutil_socketpair_retval
sysutil_unix_stream_socketpair(void)
{
    struct sysutil_socketpair_retval retval;
    int the_sockets[2];
    int sys_retval = socketpair(PF_UNIX, SOCK_STREAM, 0, the_sockets);
    if (sys_retval != 0)
    {
        die("socketpair");
    }
    retval.socket_one = the_sockets[0];
    retval.socket_two = the_sockets[1];
    return retval;
}

int main()
{
    struct sysutil_socketpair_retval retval;
    memset(&retval, 0, sizeof(retval));
    retval = sysutil_unix_stream_socketpair();
    int child_fd = retval.socket_one;
    int parent_fd = retval.socket_two;

    int pid = fork();
    if (pid < 0) {
        die("fork");
    }
    else if (pid == 0) { // child process
        char buf[] = "This is child process";
        int counter = 0;
        while (true) {
            int ret = static_cast<int>(write(child_fd, reinterpret_cast<void*>(buf), sizeof(buf)));
            if (ret < 0) {
                return ret;
            }
            std::this_thread::sleep_for(std::chrono::seconds(1));
            printf("child counter = %d\n", counter);
            counter++;
        }
        return 0;
    }
    // parent process
    char buf[1024];
    int counter = 0;
    while (true) {
        int ret = static_cast<int>(read(parent_fd, reinterpret_cast<void*>(buf), sizeof(buf)));
        if (ret < 0) {
            printf("parent read fail\n");
            continue;
        }
        printf("parent recv: %s\n", buf);
        std::this_thread::sleep_for(std::chrono::seconds(1));
        printf("parent counter = %d\n", counter);
        counter++;
    }
	return 0;
}
